1. Технология MDA. Цель и задачи дипломного проекта.

1.1 Технология Model Driven Architecture (MDA)

Model Driven Architecture (MDA) – модельно – ориентированный подход к разработке программного обеспечения.[1]

Суть этой технологии состоит в построении абстрактной метамодели управления и обмена метаданными (моделями) и задании способов ее транс¬формации в поддерживаемые технологии программирования (Java, CORBA, XML и др.).

Object Management Group (OMG) является международным, открытым членством, не для некоммерческой компьютерной индустрии стандартов консорциума. Она объединяет сотни компаний-производителей программного и аппаратного обеспечения.

Существует тесная взаимосвязь между всеми стандартами OMG. Самая последняя инициатива OMG – Model Driven Architecture (MDA). Суть подхода в том, что MDA модели являются основой для разра¬ботки программного обеспечения.

Архитектура MDA предлагает новый интегральный подход к созданию приложений и базируется на трех основных элементах:

 UML (Unified Modelling Language) унифицированный язык моделирования;

 MOF (Meta Object Facility) ¬ абстрактный язык для описания информации о моделях (язык описания метамоделей);

 CWM (Common Warehouse Metamodel) общий стандарт описания ин-формационных взаимодействий между хранилищами данных.

Внимание!
Это ОЗНАКОМИТЕЛЬНАЯ ВЕРСИЯ работы №3325, цена оригинала 500 рублей. Оформлена в программе Microsoft Word

На рис. 1.1 видно, что на центральном уровне структуры находится собственно MDA, которая «разворачивается» наружу посредством второго уровня, содержащего вышеперечисленные базовые составляющие ¬ UML, MOF и CWM, ¬ и на третьем, внешнем уровне представлены некоторые из широко известных в настоящее время программных платформ разработки: CORBA, XML, .NET, JAVA. Отметим, что на этом внешнем уровне, по замыслу OMG, могут и должны быть размещены, в принципе, и все возможные будущие технологии разработки. Этим подчеркивается тот факт, что OMG считает архитектуру MDA не просто новой технологией, а скорее «метатехнологией» создания приложений.

Рис. 1.1 Схема взаимодействия MDA с программными технологиями.

Преимущества, которые дает архитектура MDA:

 Кардинальное повышение производительности разработки (устраняется этап «ручного» программирования).

 Документированность и легкость сопровождения.

 Централизация логики функционирования.

 Облегчение доступности и управляемости разработки (UML – диаграммы, представленные в графическом виде, являются достаточно наглядными и по существу не требуют знания программирования или теоретических основ разработки реляционных баз данных).

Само понятие «разработчик программного обеспечения» может при внедрении MDA довольно сильно видоизмениться. Со смещением акцента на создание модели разработкой приложений будут заниматься не столько программисты, сколько специалисты, владеющие описываемой предметной областью. Возможно, что также в какой-то степени «пострадает» традиционное деление специалистов на разработчиков баз данных и разработчиков приложений баз данных.

Уже сейчас возможно при разработке MDA – приложений практически полностью абстрагироваться от знания конкретной СУБД. Во многих случаях нет необходимости использовать язык SQL, поскольку рассматриваемые инструменты MDA предоставляют возможность работать на более «высоком» уровне (бизнес – уровне), где становится абсолютно не важным знание конкретной структурной схемы базы данных или состава полей ее таблиц.

Advertisement
Узнайте стоимость Online
  • Тип работы
  • Часть диплома
  • Дипломная работа
  • Курсовая работа
  • Контрольная работа
  • Решение задач
  • Реферат
  • Научно - исследовательская работа
  • Отчет по практике
  • Ответы на билеты
  • Тест/экзамен online
  • Монография
  • Эссе
  • Доклад
  • Компьютерный набор текста
  • Компьютерный чертеж
  • Рецензия
  • Перевод
  • Репетитор
  • Бизнес-план
  • Конспекты
  • Проверка качества
  • Единоразовая консультация
  • Аспирантский реферат
  • Магистерская работа
  • Научная статья
  • Научный труд
  • Техническая редакция текста
  • Чертеж от руки
  • Диаграммы, таблицы
  • Презентация к защите
  • Тезисный план
  • Речь к диплому
  • Доработка заказа клиента
  • Отзыв на диплом
  • Публикация статьи в ВАК
  • Публикация статьи в Scopus
  • Дипломная работа MBA
  • Повышение оригинальности
  • Копирайтинг
  • Другое
Прикрепить файл
Рассчитать стоимость

Однако программисты – разработчики вряд ли останутся без работы, так как, с одной стороны, создание MDA – инструментария само по себе является чрезвычайно интересной, сложной и объемной задачей для них. А с другой стороны, внедрение MDA уже сейчас избавляет и самих программистов от рутинной работы, передавая большую ее часть искусственному программному интеллекту – инструментам реализации MDA.

Цель MDA.

В современных программных системах активно используются много различных стандартов и технологий промежуточного слоя – CORBA, DCOM, .Net, Web – службы, технологии, основанные на Java и т.д. Все чаще возникает потребность в интеграции и обеспечении взаимодействия систем, основанных на разных технологиях, а также в модернизации существующих программ и их переработке в соответствии с новой технологической основой. Новая архитектурная концепция, предложенная консорциумом OMG, основанная на модельно – ориентированном подходе к разработке программного обеспечения, позволяет существенно упростить и частично автоматизировать разработку, интеграцию и модернизацию систем.

В связи с большим количеством используемых и разрабатываемых стандартов и технологий стало очевидно, что попытка создать единый уни-версальный стандарт построения и взаимодействия программных систем обречена на неудачу. Примером тому стандарт CORBA, который, хотя и приобрел определенную известность, так и не занял предполагаемого для него места «универсального стандарта». Поэтому консорциум OMG принял решение перейти от «стандарта интеграции» к интеграции стандартов. Концепция MDA (Model Driven Architecture) призвана обеспечить общую основу для описания и использования большинства существующих стандартов, не ограничивая разработчиков в выборе конкретных технологий. Интеграция стандартов достигается за счет:

 введения концепции платформенно – независимой модели приложения;

 использования унифицированного инструмента (UML) для описания таких моделей;

 наличия разработанных OMG стандартных отображений моделей в среду большинства технологических платформ и программных инструментов промежуточного слоя.

Ядром MDA являются несколько стандартов – UML, MOF, CWM и XMI. Язык UML (Universal Modeling Language) используется для описания всех моделей. Совокупность метамоделей CWM (Common Warehouse Model) представляет наиболее часто используемые в базах данных и инструментах бизнес – анализа метаданные. CWM содержит большое количество различных метамоделей, описывающих функционирование бизнеса. MOF (Meta Object Facility) общий абстрактный язык для описания метамоделей, на его основе построены формальные описания метамодели для CWM и UML. Последний стандарт, XMI (XML Metadata Interchange), играет служебную роль, описывая отображение моделей MOF и UML на стандарт XML. При этом метамодели преобразуются в DTD – структуру документа, а модели в тело XML – документа. Это позволяет объединить модель и ее метамодель в одном документе и получить так называемый «само – описываемый» (self – describing) документ, содержащий не только данные, но и информацию, необходимую для их интерпретации.

В основе MDA лежит понятие платформенно – независимой модели (platform independent model, PIM). Речь идет о детальной исполняемой модели на языке действий UML (action semantics), сформулированными на OCL.

Вполне логично, что для описания PIM выбран язык UML. Этот язык принципиально позиционировался как независящий от платформ и технологий. Однако UML в своих ранних версиях не являлся «точным» языком: он только предоставлял дизайнеру возможность описать структуру и поведение системы, практически не определяя ее функционирование и используемые алгоритмы. В новый стандарт UML 2.0, который был одобрен OMG в июне 2003 года, включено большое количество средств, позволяющих описывать внутреннюю организацию и функционирование системы. Одна из основных задач, которые были решены при создании этого стандарта, превратить UML в алгоритмически полный исполнимый язык, в то же время, по возможности, не повышая уровня детализации UML-моделей.

Несмотря на то, что PIM – это детальная исполняемая модель, ее вряд ли можно использовать на практике как финальный программный продукт. UML – инструментарий нового поколения предоставляет унифицированную среду, в которой можно интерпретировать эту модель и получать исполняемый код прототипного качества. Такой код может быть крайне неэффективным, не удовлетворять некоторым функциональным требованиям, не полностью реализовывать функциональность системы и даже требовать участия человека в процессе исполнения. Инструментарий, используемый для интерпретации UML – модели, может быть полуавтоматическим и допускать вмешательство оператора. Только после привязывания к конкретной платформе можно получить код промышленного качества. Но, хотя исполнение PIM – модели и нельзя применять для решения практических задач, оно необычайно важно для целей тестирования и отладки. Фактически, у разработчиков появляется возможность получить первый прототип системы еще до начала стадии кодирования, когда сравнительно легко вносить даже существенные изменения в систему (в том числе, изменения требований и технического задания).

Многие крупные производители объявили о поддержке MDA и начале разработки соответствующих инструментов, и в ближайшее время можно ожидать выхода первых инструментариев разработки с использованием MDA. Но, вероятно, потребуется значительный период времени, чтобы инструменты развились и смогли максимально использовать возможности технологии. Пока это не сделано, значительную часть рутинной работы придется выполнять вручную.

1.2 Использование языков UML и OCL в технологии MDA

В основе MDA лежит идея выделения в качестве самостоятельного и обязательного этапа разработки логики функционирования приложения (бизнес – логики). Согласно концепции MDA разработка приложения должна начинаться с этапа создания модели приложения, которая определяет состав, структуру и поведение будущего программного продукта. Такая модель создается не на языке программирования, а посредством языка унифицированного моделирования (Unified Modelling Language, UML) и является платформенно-независимой (Platform Independent Model, PIM ), то есть при ее создании разработчик полностью абстрагируется от особенностей конкретных программных и аппаратных средств реализации приложения.

первое первое

преобразование преобразование

второе второе

преобразвание преобразование

Рис. 1.2. Взаимосвязь между PIM,PSM и кодом.

На втором этапе, после создания PIM, создаются одна или несколько плат-форменно – зависимых моделей PSM (Platform Specific Model) (см. рис. 1.2.), которые являются своеобразными адаптерами, обеспечивающими интеграцию PIM с одной или несколькими технологиями разработки программных продуктов. Кроме того, создается специальный набор программных интерфейсов, используемый в дальнейшем для взаимодействия данного приложения с другими.

На заключительном этапе, на основании PIM и PSM генерируется код при-ложения и, при необходимости, база данных. В случае наличия нескольких PSM процедура генерации может проводиться несколько раз – для каждой из используемых платформ. При этом генерация кода и баз данных осуществляется автоматически, посредством специальных инструментальных программных средств.

Таким образом, в соответствии с концепцией MDA главный акцент

при разработке приложений переносится с этапа программирования на этап создания модели. К тому же, создав модель один раз, разработчик получает принципиальную возможность генерации приложений для разных аппаратных и программных платформ.

Вследствие смещения акцента на создание модели, разработкой при-ложений будут заниматься не столько программисты, сколько специалисты, владеющие описываемой предметной областью. При этом языком описания является унифицированный язык моделирования UML.

Причиной появления Unified Modelling Language (UML) стала необходимость унифицированного подхода к описанию моделей бизнес-приложений в начале 90-х годов ХХ века. К тому времени появилось не-сколько десятков вариантов инструментария для создания подобных моде-лей, но все они были не согласованы между собой, что мешало разработке CASE – средств и вносило некоторую путаницу. CASE – средства (Computer Aided Software Engineering – разработка программного обеспечения с помощью компьютера, то есть автоматизированная разработка программного обеспечения) в тот период играли в основном роль графической надстройки над СУБД, позволяющей автоматически генерировать базу данных по ее графической схеме. У истоков разработки языка UML стояла компания Rational Software, разработавшая одно из первых CASE – средств – Rational Rose. В 1995 году консорциум OMG включился в работу по стандартизации UML, затем к разработке языка активно подключились и другие компании и после выхода нескольких промежуточных версий, в 1997 году появилась версия UML 1.0.

В настоящее время последней стандартизованной OMG версией явля-ется UML 1.4, завершается разработка версии 2.0. Развитие UML сегодня координирует консорциум OMG, который считает разработку и продвижение этого языка своим стратегическим направлением.

Характерные свойства UML:

 UML является языком визуального моделирования, то есть обеспечивает наглядное графическое представление модели в виде одной или нескольких схем;

 UML не является языком программирования и не содержит алгоритмов и операторов в обычном смысле – он в первую очередь является средством описания;

 UML, являясь платформенно-независимым языком, абстрагируется от специфики конкретных языков программирования и средств разработки.

 Язык UML базируется на объектно-ориентированном подходе и включает диаграмму классов для описания структуры и состава модели. Диаграмма классов является основой для формирования модели приложения и играет важнейшую роль при работе с продуктом Boldfor Delphi.

В рамках UML существует и развивается формальный язык для текстового описания условий, накладываемых на классы модели. Он получил название OCL (Object Constraint Language – язык объектных ограничений). OCL также играет чрезвычайно важную роль при практическом использовании MDA в Delphi.

Более точный и лаконичный способ формулировки ограничений обеспечивает язык OCL (Object Constraints Language). Вот общая характеристика этого языка.

Из языка UML в OCL заимствованы, в первую очередь, следующие концепции:

 класс, атрибут, операция;

 объект (экземпляр класса);

 ассоциация;

 тип данных (включая набор предопределенных типов Boolean, Integer, Real и String);

 значение (экземпляр типа данных).

 Для понимания языка OCL существенны определяемые в UML традиционные для объектных моделей данных различия между объектом некоторого класса и значением некоторого типа:

 объект обладает уникальным идентификатором и может сравниваться с другими объектами только по значению идентификатора; следствием этого является возможность определения операций над множествами объектов в терминах их идентификаторов;

 объект может быть ассоциирован через бинарную связь с другими объектами, что позволяет определить в OCL операцию перехода от данного объекта к связанным с ним объектам;

 в то же время значение является «чистым значением» в том смысле, что: при сравнении двух значений проверяются сами эти значения; кроме того, значения не могут участвовать в связях, поскольку понятие связи определено только для объектов классов.

 В дополнение к скалярным типам данных, заимствованным из UML, в OCL предопределены структурные типы, которые являются разновидностями типов коллекций (collection):

 математическое множество (set), неупорядоченная коллекция, не содержащая одинаковых элементов;

 мультимножество (bag), неупорядоченная коллекция, которая может содержать повторяющиеся элементы-дубликаты;

 последовательность (sequence), упорядоченная коллекция, которая мо-жет содержать элементы-дубликаты.

В OCL элементами каждого из трех типов коллекций могут быть либо объекты, либо значения.

Язык OCL предназначен, главным образом, для определения ограничений целостности данных, соответствующих модели, которая представлена в терминах диаграммы классов UML. OCL может применяться для определения ограничений, описывающих пред и постусловия операций классов, и ограничений, представляющих собой инварианты классов. При проектировании реляционных баз данных возможность определения пред и постусловий операций вряд ли может оказаться существенной. С точки зрения определения ограничений целостности баз данных более важны средства определения инвариантов классов.

1.3 Цель и задачи дипломного проекта

Целью дипломного проекта является исследование трансляции OCL итерационных операторов в программный код на языке программирования Java и разработка алгоритмов трансляции.

Для достижения отмеченной цели в дипломном проекте решались следующие задачи.

 Обзор итерационных операторов OCL и выбор операторов для трансляции.

 Разработка итерационных алгоритмов для каждого из операторов и представление их в виде диаграммы деятельности.

 Отображение каждой из полученных диаграмм деятельности в про-граммный код на языке программирования Java.

 Обобщение полученных алгоритмов и разработка обобщенного алго-ритма трансляции итерационных OCL операторов в программный код.

2. Обзор итерационных операторов OCL.

2.1 Наборы данных в OCL. Типовые предложения для специфицирования итерационных операций.

Поле с множественными значениями, а также полюс ассоциаций, в общем случае, специфицируют не один объект, а набор объектов. Поэтому для записи OCL-выражений, которые включают поля с множественными значениями и поля, определяемые ассоциацией, необходимо знать каким образом в OCL представляются наборы объектов и какие операции предопределены для этих наборов.[2]

При построении некоторых моделей возникает необходимость специ-фицировать запросы к системе с целью выбора набора объектов, удовлетворяющих заданным ограничениям. Например, может потребоваться выбрать из класса Person все объекты, для которых значение поля yearOfBirth (год рождения) равно или превышает 2000.

Для того чтобы можно было включать в OCL-ограничения выражения, оперирующие с наборами объектов, в состав языка объектных ограничений OCL включено несколько предопределенных типов наборов объектов и большое количество операций с наборами объектов.

Типы наборов объектов в OCL

На рис. 2.1 приведена диаграмма классов, моделирующая структуру системы предопределенных типов наборов объектов, используемых в языке объектных ограничений OCL.

Как видно, на рис. 2.1, структура типов наборов объектов в OCL представляет собой четыре реальных класса Set (множество), OrderedSet (упорядоченное множество), Bag (мешок) и Sequence (последовательность), являющихся подклассами абстрактного суперкласса Collection (набор).

Рис. 2.1. Типы предопределенных наборов объектов в OCL.

Абстрактный тип Collection используется для определения опера-ций, общих для любого набора объектов, а в OCL-выражениях используются только типы, определяемые реальными классами Set, OrderedSet, Bag и Sequence.

Набор объектов типа Set состоит из однотипных объектов и не содержит дубликатов объектов. Отдельный объект может входить в набор только один раз. Объекты в наборе типа Set располагаются в произвольном порядке и неупорядочены.

Набор объектов типа OrderedSet отличается от набора объектов типа Set только тем, что объекты в нем упорядочены. Упорядоченность объектов в этом наборе не следует понимать в смысле упорядоченности, полученной в результате сортировки (размещения объектов в порядке возрастания либо убывания их значений). Упорядоченность объектов в наборе OrderedSet следует понимать в смысле очередности (для всех объектов набора OrderedSet известно, какой объект предшествует данному объекту и какой объект следует за данным объектом).

Набор объектов типа Bag отличается от набора объектов типа Set тем, что в нем допустимы копии объектов. Один и тот же объект может входить в набор типа Bag несколько раз. Объекты в наборе типа Bag располагаются в произвольном порядке и неупорядочены.

Набор объектов типа Sequence отличается от набора объектов типа Bag тем, что объекты в нем упорядочены. Упорядоченность объектов в этом наборе следует понимать также как и упорядоченность объектов в наборе типа OrderedSet.

В том случае, когда набор состоит из объектов примитивных типов (числа, булевы данные и символы), а также из строк символов, то наборы объектов могут быть заданы перечислением значений объектов в фигурных скобках. Имя типа набора помещается перед фигурными скобками. Например.

Set{1, 2, 88, 7}

Bag{1, 2, 88, 2}

Set{„red‟, „green‟, „black‟, „yellow‟}

OrderedSet{„red‟, „orange‟, „yellow‟, „green‟}

Sequence{1.21, 3.44, 9.81, 7.42}

В том случае, когда перечислением задается набор, состоящий из не-прерывной последовательности целых чисел, допускается не перечислять все числа, а указать первое и последнее числа последовательности, разделенные двоеточием.

Например, набор

Set{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

можно записать в виде

Set{1..10}

Задание набора объектов путем перечисления их значений используется, главным образом, в OCL-ограничениях с init-предложением для задания начальных значений полей и полюсов ассоциаций со множественными значениями. Например, список авторов, моделируемый полем authors: String [1..*] может быть задан следующим OCL- ограничением.

context Book::authors:String[1..*]

init: Set{„Ильф‟, „Петров‟}

В OCL-выражениях, которые используются во всех остальных видах OCL- ограничений, наборы задаются неявно в виде имени поля или полюса ассоциации со множественными значениями.

Базовые операции с наборами объектов в OCL

Все операции OCL, допустимые для наборов объектов, обладают следующим фундаментальным свойством. Операция не изменяет набор, к которому она применяется. Исходный набор объектов всегда остается неизменным, а в некоторых случаях создается новый набор. Современная версия OCL включает несколько десятков предопределенных операций над наборами объектов. Некоторые операции применимы для всех типов наборов, а некоторые – специализированы для конкретных типов. В таблице, на рис. 2.2, приведен перечень операций, применимых для всех типов наборов объектов.

Операция «равенство» определяет равенство различным образом, в зависимости от типа набора объектов.

Два набора объектов типа Set считаются равными, если все объекты первого набора присутствуют во втором наборе и наоборот.

Два набора объектов типа OrderedSet считаются равными, если (1) они равны в смысле наборов типа Set и (2) порядок размещения объектов в обоих наборах совпадает. Два набора объектов типа Bag считаются равными, если (1) все объекты первого набора присутствуют во втором наборе и наоборот, а также (2) количество одинаковых объектов в обоих наборах совпадает.

Оператор в OCL-выражении Описание операции

= Операция «равенство». Сравнивает два на-бора объектов и возвращает значение true, если наборы равны.

<> Операция «не равенство». Сравнивает два набора объектов и возвращает значение true, если наборы не равны.

size() Определяет количество элементов в наборе объектов

isEmpty() Возвращает значение true, если набор объектов не содержит ни одного элемента.

notEmpty() Возвращает значение true, если набор объектов содержит один или несколько элементов.

count(object) Возвращает количество элементов object в наборе объектов.

including(object) Возвращает новый набор объектов, полу-ченный из исходного набора путем добав-лением в него элемента object.

excluding(object) Возвращает новый набор объектов, полу-ченный из исходного набора путем исклю-чения из него элемента object.

includes(object) Возвращает значение true, если набор объектов содержит элемент object.

excludes(object) Возвращает значение true, если набор данных не содержит элемент object.

includesAll(collection) Возвращает значение true, если набор со-держит все объекты из collection.

excludesAll(collection) Возвращает значение true, если набор не содержит ни одного объекта из collection.

sum() Для наборов числовых типов возвращает сумму всех значений объектов.

Рис. 2.2. Базовые предопределенные операции OCL над наборами объектов.

Два набора объектов типа Sequence считаются равными, если они равны в смысле наборов типа Bag и порядок размещения объектов в обоих наборах также совпадает.

Операция «не равенство» противоположна операции «равенство». Операция including(object) работает следующим образом.

Для наборов объектов типа Bag, операция возвращает новый набор, полученный из исходного, путем добавления в него объекта object.

Для наборов объектов типов Set и OrderedSet объект object до-бавляется в результатный набор только в том случае, если он отсутствует в исходном наборе. В противном случае операция возвращает исходный набор.

Для упорядоченных наборов объектов типа OrderedSet и Sequence новый объект object добавляется в конец набора.

Операция excluding(object) возвращает новый набор объектов, полученный из исходного набора, путем удаления из него объекта object. Для наборов объектов Set и OrderedSet удаляется только один объект, а для упорядоченных наборов типа OrderedSet и Sequence удаляются все копии объекта object.

При записи операции над набором объектов в OCL-выражениях ис-пользуется следующая конструкция.

<collection> -> <operator>(<parameter>)

collection – спецификация набора объектов;

operation – имя оператора;

parameter – параметр оператора.

Все операции над наборами объектов обозначаются при помощи символа стрелки, который, часто, составляется из символов «минус» и «больше». Стрелка направлена слева направо. Слева от символа стрелки специфицируется набор объектов, к которому применяется операция, в виде имени поля или полюса ассоциации со множественными значениями. Справа от символа стрелки записывается имя оператора с входным параметром в круглых скобках. В тех случаях, когда используется оператор без параметров скобки остаются пустыми.

Рассмотрим пример, иллюстрирующий использование оператора size в OCL- выражении. На рис. 2.3 приведена диаграмма классов, моделирующая структуру приложения, осуществляющего автоматизированный учет продажи билетов на авиарейсы.

Система состоит из трех ассоциированных классов: Flight (рейс), Aircraft (летательный аппарат) и Person (личность). Класс Flight мо-делирует множество авиарейсов. Наибольшее количество билетов, которое может быть продано на авиарейс определяется типом летательного аппарата, закрепленного за этим рейсом.

Flights [0..*]

Airplane[1..1]

Flights [0..1]

Passengers [0..*]

Рис. 2.4. Система учета продажи билетов на авиарейсы.

Множество доступных летательных аппаратов моделируется классом Aircraft, ассоциированным с классом Flight. Полюса этой ассоциации ин-терпретируются следующим образом. Полюс airplane[1..1] означает, что с одним объектом класса Flight связан только один объект класса Aircraft (рейс выполняется одним летательным аппаратом), а полюс flights[0..*] означает, что с одним объектом класса Aircraft может быть связано несколько объектов класса Flight (летательный аппарат мо-жет использоваться при выполнении нескольких различных рейсов).

Пассажиры, участвующие в авиарейсах, моделируются классом Person, который, также ассоциирован с классом Flight. Полюс flights[1..1] означает, что с одним объектом класса Person связан только один объект класса Flight (в данном, конкретном рейсе принимает участие одна личность из класса Person), а полюс passengers[0..*] означает, что с одним объектом класса Flight может быть связано несколько объектов класса Person (в одном авиарейсе может принимать участие некоторое количество личностей).

При учете количества проданных билетов естественным является сле-дующее ограничение: «на авиарейс может быть продано такое количество билетов, которое не превышает количества пассажирских сидений в лета-тельном аппарате, закрепленном за данным рейсом». Это ограничение должно быть истинным для любого объекта класса Flight и может быть специфицировано при помощи следующего инварианта.

context Flight

inv:self.passengers ->size()<= airplane.numbOfSeats

— numbOfSeats поле класса Aircraft

Булево выражение в приведенном инварианте представляет собой не-равенство. Левая часть неравенства – это результат применения операции size к набору объектов типа Person, который специфицирован именем поля класса Flight (или именем полюса ассоциации) passengers. Операция size возвращает количество объектов класса Person, ассоциированных с одним объектом класса Flight. Правая часть неравенства – это, по сути, значение поля numbOfSeats (количество кресел) класса Aircraft. Поскольку поле numbOfSeats не принадлежит классу Flight, то для доступа к нему не-обходимо использовать составное имя, состоящее из имени объекта класса Aircraft (или имени полюса ассоциации) airplane и имени поля numbOfSeats.

2.2 Обзор итерационных операций OCL.

Часто операции с наборами объектов являются итерационными. Итерационная операция последовательно получает доступ ко всем объектам набора и оценивает их при помощи параметра операции. Параметр итерационной операции, в общем случае, представляет собой выражение, которое соответствует характеру операции. Например, для того, чтобы выбрать из класса Person все объекты, для которых значение поля yearOfBirth (год рождения) равно или превышает 2000, понадобится итерационная операция, параметр которой представляет собой выражение, детерминирующее требуемые объекты. Современная версия OCL предопределяет десятки итерационных операций для наборов объектов. В таблице, на рис. 3.46, приведен перечень основных итерационных операций, применимых для всех типов наборов объектов.

При записи итерационной операции с набором объектов в OCL-выражениях, чаще всего, используется следующая конструкция.

<collection> -> <operator>(<expr>)

collection – спецификация набора объектов;

operator – имя итерационного оператора;

expr – выражение-параметр итерационного оператора.

В параметр итерационного оператора может быть введена итерационная переменная, специфицирующая объекты набора, которые оцениваются при помощи параметра. Тип итерационной переменной всегда совпадает с типом объектов набора, поэтому, при записи OCL-выражений, его не указывают. В случае использования итерационной переменной, итерационная операция специфицируется при помощи одной из следующих конструкций.

<collection> -> <operation>(<iteration varia-ble>:<type>|<expr>)

<collection> -> <operation>(<iteration varia-ble>|<expr>)

iteration variable – имя итерационной переменной;

type – тип итерационной переменной.

expr – выражение-параметр итерационного оператора.

Итерационного оператора Описание операции

any(expr) Возвращает случайно выбранный объект нара, для которого значение expr равно true.

collect(expr) Возвращает новый набор, созданный из исходного набора в соответствии со значением expr.

exists(expr) Возвращает значение true, если, хотя бы для одного объекта набора, значение expr равно true.

forAll(expr) Возвращает значение true, если для всех объектов набора значение expr равно true.

isUnique(expr) Возвращает значение true, если для всех объектов набора значение expr является никальным.

one(expr) Возвращает значение true, если только для одного объекта набора значение expr равно true.

select(expr) Возвращает те объекты набора, для которых значение expr равно true.

reject(expr) Возвращает те объекты набора, для которых значение expr равно false.

sortedBy(expr) Возвращает объекты набора отсортированные в соответствии со значением expr.

iterate(. . .) Производит итеративную операцию над всеми объ-ектами набора.

Рис. 2.5. Предопределенные итерационные операции OCL над наборами

объектов.

В ряде случаев, введение итерационной переменной в параметр является избыточной детализацией описания итерационной операции и усложняет чтение и OCL- ограничения и понимание его смысла.

Оператор any позволяет выбрать один, произвольный объект из набора объектов, который удовлетворяет условию, сформулированному в виде выражения-параметра expr. Выражение-параметр оператора any является булевым выражением, которое принимает значение true в том случае, когда оцениваемый объект набора удовлетворяет условию выбора. Если ни один из объектов набора не удовлетворяет условию выбора, то результат операции any является неопределенным.

Рассмотрим применимость операции any на примере. Уточним модель учета продажи билетов на авиарейсы, приведенную на рис. 2.5 следующим образом. Введем в класс Flight новый метод-запрос, возвращающий ссылку на пассажира, которому авиа — компания вручает приз. Будем считать, что авиакомпания вручает приз только одному из пассажиров авиарейса, случайно выбираемому среди тех, кто, в течение года, пролетел более 9999 км. Требуемое уточнение модели можно осуществить при помощи следующего OCL-ограничения с def-предложением.

context Flight

def:getWinner():Person =

self.passengers -> any(passengers.yearDistance > 9999)

— yearDistance – поле класса Person

Приведенное ограничение вводит в класс Flight новый метод-запрос с именем getWinner (получить победителя), который осуществляет выбор пассажира в соответствии с требуемым условием. При описании способа формирования возвращаемого значения метода getWinner использована итерационная операция any, которая применена к набору объектов passengers. Этот набор представляет собой те объекты класса Person, которые ассоциированы с одним объектом класса Flight. По сути, набор объектов passengers моделирует пассажиров авиарейса. Параметр-выражение операции any принимает значение true во всех случаях, когда значение поля yearDistance (годовое расстояние) для объекта класса Person больше 9999. Составное имя поля passengers.yearDistance определяет навигацию из класса Flight, указанного в контексте, к классу Person.

Оператор collect позволяет сформировать новый набор объектов из исходного набора объектов. Отличительной особенностью оператора collect является то, что тип нового набора объектов отличен от типа исходного набора объектов. Иными словами новый набор не является поднабором исходного набора. Объекты нового набора формируются из объектов исходного набора в соответствии со значением параметра операции collect.

Рассмотрим пример использования оператора collect. Уточним модель учета продажи билетов на авиарейсы, приведенную на рис. 2.4 следующим образом. Введем в класс Flight метод-запрос, формирующий и возвращающий набор, состоящий из фамилий всех пассажиров, участвующих в рейсе. Требуемое уточнение модели можно осуществить при помощи следующего OCL-ограничения.

context Flight

def:getNames():Bag(String) =

self.passengers -> collect(passengers.name)

— name – поле класса Person

Ограничение вводит в класс Flight метод-запрос с именем getNames (получить фамилии), который возвращает набор объектов типа String. Тип всего набора Bag, поскольку пассажиры могут иметь совпа-дающие имена. При описании способа формирования возвращаемого значения метода getNames использован итерационный оператор collect, который применен к набору объектов passengers, моделирующего пассажиров конкретного рейса. Параметром оператора collect является поле name класса Person. Из каждого объекта типа Person операция collect формирует объект типа String, значением которого является фамилия пассажира. Имя поля passengers.name является составным и определяет навигацию из класса Flight, указанного в контексте, к классу Person.

Оператор exists позволяет определить присутствует ли в наборе хотя бы один объект, удовлетворяющий условию, сформулированному при помощи параметра expr. Оператор exists возвращает значение true, если искомый объект присутствует в наборе и значение false, если искомый объект отсутствует в наборе.

Рассмотрим пример использования оператора exists. Введем в класс Flight на рис. 2.4 еще один метод-запрос, позволяющий ответить на вопрос: «Участвует ли в рейсе пассажир по фамилии Жванецкий». OCL — ограничение, специфицирующее требуемый метод имеет вид.

context Flight

def:getPassenger(who:String):boolean =

self.passengers -> exists(passengers.name = „Жванецкий‟)

— name – поле класса Person

Ограничение вводит в класс Flight метод-запрос с именем getPassenger (получить пассажира), с входным параметром типа String, который возвращает значение булевого типа. При описании способа формирования возвращаемого значения метода getPassenger использован итерационный оператор exist, который применен к набору объектов passengers, моделирующего пассажиров конкретного рейса. Параметр-выражение оператора exist принимает значение true во всех случаях, когда значение поля name для объекта класса Person равно литралу „Жванецкий‟

Оператор forAll позволяет определить удовлетворяют ли все объекты набора условию, сформулированному при помощи параметра оператора expr. Оператор forAll возвращает значение true, только в том случае, когда все объекты набора удовлетворяют условию. Если хотя бы один из объектов не удовлетворяет условию, то оператор forAll возвращает значение false.

Рассмотрим следующее OCL-ограничение, уточняющее модель, приведенную на рис. 2.4 и иллюстрирующее использование оператора forAll.

context Flight

inv: self.passengers ->

forAll(passengers.registration = „зарегистрирован‟)

— registration – поле класса Person

Приведенное ограничение специфицирует инвариант класса Flight, который на русском языке может быть сформулирован следующим образом: «Все пассажиры рейса должны быть зарегистрированы». В OCL-выражении инварианта оператор forAll применен к набору объектов passengers. Параметр оператора представляет собой булево выражение, возвращающее значение true, если значение поля registration класса Person равно „зарегистрирован‟

Операторы forAll и exists логически взаимозаменяемы и могут использоваться для записи OCL-выражений имеющих одинаковый смысл. Приведенные ниже конструкции логически эквивалентны.

<collection> -> exists(<expr>)

not <collection> -> forAll(not <expr>)

Оператор isUnique позволяет получить ответ на вопрос: «Обладают ли все объекты набора уникальным признаком?» Для каждого объекта набора оператор isUnique проверяет, уникальна ли его характеристика, заданная параметром оператора и возвращает значение true если все объекты набора имеют различные значения отмеченной характеристики. Если среди объектов набора присутствуют хотя бы два объекта с совпадающими значениями характеристики, оператор isUnique возвращает значение false. Одним из способов реализации объектной идентичности является использование ключа класса. Ключом класса мы называем те поля класса, совокупное значение которых уникально идентифицирует объект. Оператор isUnique может быть использована для проверки того, являются ли выбранные поля класса его ключом. Проиллюстрируем применимость оператора на примере уточнения модели, приведенной на рис. 2.4. Введем в класс Flight метод-запрос, ко-торый проверяет, являются ли уникальными имена и фамилии пассажиров авиарейса. Иными словами, новый метод-запрос должен ответить на вопрос о том, могут ли поля класса Person, хранящие имя и фамилию, быть ключом для набора объектов, моделирующих пассажиров авиарейса. Специфицируем этот метод при помощи следующего OCL-ограничения.

context Flight

def:getUniqueness():boolean =

self.passengers -> isUnique(passengers.fName.concat(passengers.sName))

— firstName и secondName– поля класса Person

Приведенное ограничение вводит в класс Flight новый метод-запрос с именем getUniqueness (получить уникальность), который осуществляет проверку уникальности имени и фамилии пассажиров авиарейса. При описании способа формирования возвращаемого значения метода getUniqueness использована итерационный оператор isUnique, кото-рый оперирует с объектами набора passengers. Параметр оператора isUnique представляет собой конкатенацию полей firstName (имя) и secondName (фамилия) класса Person. Поскольку класс Person не указан в контексте, использованы составные имена для полей firstName и secondName.

Оператор one позволяет получить ответ на вопрос: «Есть ли, среди объектов набора, в точности один, удовлетворяющий заданному условию?» Условие задается булевым выражением-параметром оператора one. Оператор one проверяет каждый из объектов набора на соответствие заданному условию и возвращает значение true, если соответствие имеет место в точности для одного объекта. Если среди объектов набора нет ни одного объекта, соответствующего заданному условию, или имеется несколько таких объектов, то оператор one возвращает значение false.

Оператор select формирует новый набор объектов из исходного набора. Новый набор является частью исходного набора и имеет тип исходного набора. Параметром оператора select является булево выражение, которое специфицирует критерий выбора объектов их исходного набора. Вновь сформированный набор содержит только те объекты из исходного набора, для которых значение параметра оператора select равно true.

Проиллюстрируем применимость оператора select на примере системы учета продажи билетов на авиарейсы (см. рис. 2.4). Введем в класс Flight метод-запрос, возвращающий ссылки на всех пассажиров, которые, воспользовавшись услугами авиа- компании, в течение года, пролетели более 9999 км. Такое уточнение модели можно сделать при помощи следующего OCL-ограничения.

context Flight

def:getAllWinners():Set(Person) =

self.passengers -> select(passengers.yearDistance > 9999)

— yearDistance – поле класса Person

Ограничение вводит в класс Flight новый метод-запрос с именем getAllWinners (получить всех победителей), который возвращает набор ссылок на объекты типа Person. Предполагается, что в этом наборе нет одинаковых объектов, по- этому набор возвращаемых ссылок имеет тип Set. При описании способа формирования возвращаемого значения метода getAllWinners использован итерационный оператор select, который оперирует с каждым объектом набора passengers. Напомним, что набор объектов passengers моделирует пассажиров авиарейса. Параметр-выражение оператора select принимает значение true во всех случаях, когда значение поля yearDistance (годовое расстояние) для объекта класса Person больше 9999.

Оператор reject, в некотором смысле, противоположен оператору select. Он позволяет сформировать новый набор объектов из исходного набора, который является частью исходного набора, и объекты которого имеют тип исходного набора. Параметром оператора reject является булево выражение, которое специфицирует критерий выбора объектов их исходного набора. Вновь сформированный набор содержит те объекты из исходного набора, для которых значение параметра оператора reject равно false.

Оператор iterate является наиболее фундаментальным и наиболее общим итерационным оператором. Все, ранее изученные, итерационные операторы могут рассматриваться как частные случаи оператора iterate. Оператор iterate имеет следующую структуру.

<collection> -> iterate(<variable>:<vType>;

<result>:<rType> = <initialValue>|

<expr-with-variable-and-result>)

collection – спецификация набора объектов;

variable – имя итерационной переменной;

vType – тип итерационной переменной;

result – переменная-аккумулятор результата итерационной операции;

rType – тип переменной-аккумулятора;

initialValue – выражение, задающее начальное значение аккумулятору;

expr-with-variable-and-result – выражение-параметр итерационного опера-тора.

Перед началом выполнения оператора iterate в переменную-аккумулятор помещается начальное значение. Выражение-параметр итерационного оператора специфицирует действия, которые, при каждой итерации, выполняются над содержимым аккумулятора и значением итерационной переменной. На каждой итерации итерационная переменная ссылается на очередной объект набора. Результат выполнения действия, задаваемого выражением-параметром, записывается в аккумулятор и заменяет, в нем, предыдущее значение.

Проиллюстрируем применимость оператора на примере OCL-выражения, специфицирующего итерационный процесс нахождения суммы множества целых чисел.

Set{1-1000} -> iterate(i:int; sum:int = 0 | sum +i)

В приведенном примере набор объектов представляет собой множество целых чисел от 1 до 100. Целочисленная итерационная переменная с именем i, на каждой итерации, принимает значение очередного целого числа. Переменная-аккумулятор с именем sum принимает начальное значение, равное 0. Выражение-параметр задает действие, заключающееся в суммировании значения аккумулятора со значением итерационной переменной.

Рассмотрим еще один пример использования операции iterate. Введем в систему учета продажи билетов на авиарейсы (см. рис. 2.4) метод-запрос, возвращающий ссылки на всех пассажиров-женщин, участвующих в авиарейсе. OCL-ограничение, специфицирующее этот метод-запрос, приведено на рис. 2.6

context Flight

def:getWomen():Set(Person) =

self.passengers -> iterate(prs:Person; resultSet:Set(Person) = Set{}|

if passengers.gender = „female‟

then resultSet.including(prs)

else resultSet

endif

— gender – поле класса Person

Рис. 2.6. Пример использования операции iterate для специфицирования метода-запроса класса Flight (см. рис. 2.4).

Метод getWomen (получить женщин) возвращает множество ссылок на объекты класса Person. Ссылки формируются оператором iterate. Оператор осуществляет итерационную обработку объектов набора passengers, моделирующего пассажиров авиарейса. Итерационная переменная этого оператора с именем prs, является ссылочной переменной типа Person. Переменная-аккумулятор с именем resultSet (результатный набор) представляет собой Set-набор объектов типа Person. Начальное значение аккумулятора — пустое множество, описанное в виде Set{}. Выражение-параметр специфицировано при помощи «if-then-else» оператора, который добавляет новую ссылку в аккумулятор (resultSet.Including (prs)) только в том случае, если значение поля gender (пол) принимает значение „female‟.

3. Представление OCL итерационных операторов стандартны-ми поведенческими структурами

Первым шагом, в процессе трансляции OCL итерационных операторов в программный код, является синтез моделей алгоритмов, соответствующих итерационных процессов в виде диаграмм деятельности, состоящих из стандартных поведенческих структур. В третьем разделе диплома приводятся основные сведения о диаграмме деятельности, краткий обзор стандартных поведенческих структур и примеры, иллюстрирующие синтез моделей алгоритмов соответствующих итерационным операторам select и collect.

3.1. Диаграмма деятельности и стандартные поведенческие структуры

Поведение программной системы, особенно в тех случаях, когда имеет место нарушение естественного порядка следования предложений, удобно моделировать графически, при помощи диаграммы деятельности унифицированного языка моделирования UML. [3]

В диаграмме деятельности поведение рассматривается как последова-тельности шагов-деятельностей, приводящих к достижению одной или не-скольких целей. Деятельность понимается в широком смысле. Это либо вы-полнение отдельного предложения, либо выполнение блока предложений, либо выполнение отдельного метода, либо выполнение группы логически связанных методов. При помощи специальных графических символов диа-грамма деятельности легко моделирует как линейные блоки, так и ветвления в программном коде, организуемые при помощи оператора if.

На рис. 3.2(б) приведены две диаграммы деятельности, моделирующие поведение программы, содержащей оператор if типа «одно условие — один блок» (слева) и оператор if типа «одно условие — два блока» (справа).

Начало диаграммы деятельности обозначается стартовым символом, представляющим собой жирную точку, а завершение диаграммы — симво-лом завершения, который изображается в виде жирной точки внутри окружности. Символ завершения соответствует некоторому целевому состоянию.

Графическим символом деятельности является прямоугольник с закругленными углами, а сама диаграмма деятельности представляет собой множество графических символов деятельности, связанных между собой символами переходов от предыдущей деятельности к последующей.

На рис. 3.2(б) символы деятельности использованы для моделирования деятельности по проверке истинности условия ветвления и для моделирования блока предложений. При отображении диаграммы деятельности в программный код важно знать и помнить следующее правило. Каждый графический символ деятельности, моделирующий блок предложений, порождает пару фигурных скобок в программном коде.

Графический символ перехода, или ветвь, изображается в виде обыкновенной стрелки, исходящей из символа предыдущей деятельности и входящей в символ последующей деятельность.

Кроме графических символов деятельности и перехода, а также символов начала и завершения, диаграмма деятельности использует графические символы ветвления и соединения, изображаемые в виде ромбов.

Символ ветвления имеет одну входящую ветвь и две исходящие ветви. На рис. 3.2(б) каждая из исходящих ветвей символа ветвления соответствует одному из значений булевого выражения-условия. Будем исходящую ветвь символа ветвления, которая соответствует значению false, называть false-ветвью, а исходящую ветвь, соответствующую значению false, называть false-ветвью. На рис. 3.2(б) true-ветвь направлена на графический символ деятельности, который моделирует работу блока, предложения которого выполняются в том случае, если булево выражение принимает значение true. А false-ветвь направлена либо на графический символ деятельности, который моделирует работу блока, который выполняется в случае, если булево выражение принимает значение false (тип «одно условие — два блока»), либо на символ соединения, ведущий к символу завершения диаграммы деятельности (тип «одно условие — один блок»).

Символ соединения имеет две входные ветви и одну выходную. Этот символ используется для моделирования того места на диаграмме, где за-вершается участок с разветвлением кода и начинается линейный участок кода. Ясно, что на диаграмме деятельности количество символов ветвления должно быть равно количеству символов соединения.

В ряде случаев логика разветвлений может быть весьма изощренной, и при кодировании легко совершить как синтаксические, так и логические ошибки. Моделирование поведения системы при помощи диаграммы дея-тельности позволяет уменьшить количество возможных ошибок.

Многие математические алгоритмы на основе итераций были придуманы задолго до изобретения компьютеров и программирования. В математической литературе они описаны на естественном языке с включением математических символов и формул.

Непосредственная трансляция описаний математических методов в программный код является ментально трудной задачей, которая чревата появлением в программном коде логических ошибок. Более рациональной является технология, которая предполагает двухэтапную трансляцию естественно-языкового описания алгоритма в программный код.

На первом этапе словесное описание алгоритма транслируется в мо-дель на основе диаграммы деятельности. Модель представляет собой диа-грамму, которая отражает пошаговую суть алгоритма и позволяет проследить потоки деятельностей от начальной деятельности до деятельности, приводящей к достижению цели. Графическое представление алгоритма позволяет легко проверить логику будущего кода.

На втором этапе диаграмма деятельности транслируется в код. Для этого достаточно знать, каким образом структурные элементы модели отображаются в программный код на том или ином языке программирования.

При построении модели целесообразно использовать не исходные графические символы-примитивы диаграммы деятельности (стартовый символ, символ деятельности, символ перехода, символ ветвления, символ соединения и другие), а готовые структуры, моделирующие набор стандартных типовых поведений, из которых строится любой алгоритм. К таким типовым поведенческим структурам относятся: блок предложений; модели выбора альтернативных блоков, приведенные на рис. 3.2(б), и модели циклов, приведенные на рис. 3.1. Назовем, для краткости, эти типовые структуры: (1) структура типа блок, (2) структура типа развилка и (3) структура типа цикл. Модели типовых поведенческих структур приведены на рис. 3.3.

Каждая из типовых поведенческих структур обладает только одни стартовым символом и только одним символом завершения. Из этого факта следуют два способа конструирования моделей алгоритмов из типовых поведенческих структур.

Типовые структуры могут соединяться последовательно и в любой комбинации и, следовательно, первым способом конструирования моделей алгоритмов из типовых поведенческих структур является последовательное соединение типовых структур.

String rightPassword = “a4b3c2d1”

String password;

while (true)

{

System.out.println (“Введите пароль”);

// ввод пароля в password

if (passworld == rightPassword) break;

}

Рис. 3.1. Фрагмент кода, иллюстрирующий использование условного оператора break для выхода из «бесконечного» цикла

Второй способ конструирования моделей алгоритмов из типовых поведенческих структур нам уже известен — это вложение одной из типовых структур в блок другой типовой структуры. При вложении одной структуры в блок другой могут использоваться разнотипные структуры. Например, в один блок структуры типа развилка может вкладываться структура типа цикл, а в другой — еще одна структура типа развилка. Степень вложения, по крайней мере, умозрительно, не ограничена.

Комбинируя отмеченные способы конструирования моделей алгоритмов из типовых поведенческих структур, можно построить модели сколь угодно сложных алгоритмов.

Для комментирования элементов модели используется графический символ комментария, который представляет собой стилизованное изображение прямоугольного листа бумаги с загнутым верхним правым углом. Символ комментария соединяется с комментируемым элементом модели при помощи пунктирной линии.

Рис. 3.2. Типовые поведенческие структуры алгоритмов.

а) структура типа блок; б) варианты структуры типа развилка;

в) варианты структуры типа цикл.

3.2. Представление оператора select стандартными поведенче-скими структурами

Опишем некоторую модель, которую будем, в дальнейшем, использовать для представления OCL операторов select и collect при помощи стандартных поведенческих структур.

На рис. 3.3. приведена диаграмма классов, которая будем рассматривать как модель логической схему базы данных некоторой авиакомпании, занимающейся пассажирскими превозкаами.

Рис. 3.3. Модель базы данных авиакомпании.

Модель состоит из трех ассоциированных классов: Flight, Aircraft и Passenger и содержит информацию о рейсах, выполненных авиакомпанией в течение года.

Класс Flight моделирует множество авиарейсов, которые авиакомпания выполнила в течение года.

Множество летательных аппаратов, которые авиакомпания использо-вала, в течение года, моделируется классом Aircraft, ассоциированным с классом Flight. Полюса этой ассоциации интерпретируются следующим образом. Полюс airplane[1..1] означает, что с одним объектом класса Flight связан только один объект класса Aircraft. Иными словами, конкретный рейс выполняется одним летательным аппаратом. Полюс flights[0..*] означает, что с одним объектом класса Aircraft может быть связано несколько объектов класса Flight. Иными словами, один и тот же летательный аппарат может использоваться при выполнении нескольких различных рейсов.

Все пассажиры, которые воспользовались услугами авиакомпании в течение года, моделируются классом Passenger, который также ассоциирован с классом Flight. Полюс flight[1..1] означает, что с одним объектом класса Passenger связан только один объект класса Flight. Иными словами, конкретный пассажир из класса Passenger либо участвует в выполнении рейса, либо не участвует. Полюс onBoard[1..*] означает, что с одним объектом класса Flight может быть связано несколько объектов класса Passenger. Иными словами в одном авиарейсе может принимать участие некоторое количество пассажиров.

В классы включено минимальное количество полей и методов. Использованы только те поля, которые необходимы для записи требуемых OCL-ограничений. Так, например, в класс Passenger включены три поля: (1) поле name моделирует фамилию пассажира; (2) поле annualDistance моделирует расстояние, которое пассажир пролетел рейсами авиакомпании в течение года; (3) поле gender моделирует пол пассажира.

Уточним модель, приведенную на рис. 3.3, и введем в класс Flight метод-запрос, который на русском языке может быть сформулирован сле-дующим образом: «Из всех пассажиров данного авиарейса выбрать только тех, кто в течение года пролетел более 9999 км.»

Используя OCL-ограничение с def–предложением это уточнение можно записать так, как это приведено на рис. 3.4.

context Flight

def: getWinners():Set(Passenger) =

self.onBoard -> select(onBoard.annualDistance > 9999)

Рис. 3.4. OCL-ограничение с оператором select.

Метод-запрос имеет имя getWinners. Метод getWinners не имеет входных параметров и возвращает набор объектов типа Set, состоящий из объектов типа Passenger.

Итерационная операция select применяется к набору объектов, который специфицирован полюсом ассоциации onBoard. Операция select, на каждой итерации сравнивает поле annualDistance объекта из набора onBoard с числом 9999. В результатный набор помещается ссылка на тот объект класса Passenger для которого выражение onBoard.annualDistance > 9999 принимает значение true.

По сути, нашей задачей является синтез модели алгоритма, который реализует последнюю строчку в тексте, приведенном на рис. 3.4.

Прежде чем приступать к синтезу отмеченной модели примем некоторые допущения.

Допущение 1.

Будем считать, что все объекты классов Flight, Aircraft и Passenger уже созданы, проинициализированы и размещены в памяти компьютера.

Допущение 2.

Создан, и размещен в памяти результатный массив ссылок на объекты класса Passenger, которые будут отобраны операцией select при работе метода getWinners. Будем считать, что это одномерный массив с именем winners.

После сделанных допущений у нас имеется вся информация, необхо-димая и достаточная для синтеза алгоритма. Диаграмма деятельности алгоритма, реализующего действия, закодированные в строке

self.onBoard -> select(onBoard.annualDistance > 9999)

приведена на рис. 3.5

Как видно на рис. 3.5 основная часть алгоритма, моделирующего работу оператора select представляет собой структуру типа цикл с проверкой вначале в которую вложена структура типа развилка с одним блоком.

В начальной части алгоритма инициализируются две переменные i и j. Переменная i является переменной-индексом массива onBoard и одно-временно параметром цикла. Переменная j является переменной-индексом массива winners.

Условием окончания итераций является выражение

i < onBoard.lenght

Иными словами, количество итераций равно количеству элементов массива onBoard.

При каждой итерации проверяется истинность булевого выражения

onBoard[i].annualDistance > 9999

Если это выражение принимает значение true, то в массив winners записывается текущая ссылка массива onBoard.

Рис. 3.5. Диаграмма деятельности, моделирующая работу оператора

select в ограничении, приведенном на рис 3.5

i = 0;

j = 0;

while(i < onBoard.lenght)

{

if(onboard[i].annualDistance > 9999)

{

winners[j] = onboard[i];

j++;

}

i++;

}

Значение переменной i увеличивается на единицу при каждой итера-ции, а значение переменной j увеличивается на единицу только в том случае, когда произошла запись ссылки в массив winners.

3.3. Представление оператора collect стандартными поведен-ческими структурами

Уточним модель, приведенную на рис. 3.3, и введем в класс Flight метод-запрос, который на русском языке может быть сформулирован сле-дующим образом: «Сформировать список фамилий пассажиров данного авиарейса».

Используя OCL-ограничение с def–предложением это уточнение можно записать так, как это приведено на рис. 3.6.

context Flight

def: getNames():Bag(String) =

self.onBoard -> collect(onBoard.names)

Рис. 3.6. OCL-ограничение с оператором collect.

Ограничение, приведенное на рис 3.6, вводит в модель новый метод с именем getNames, который возвращает набор объектов типа String, со-держащий фамилии пассажиров, находящихся на борту авиалайнера. Этот набор объектов имеет тип Bag, поскольку предполагается, что на борту авиалайнера, выполняющего некоторый рейс, могут находиться пассажиры с одинаковыми фамилиями. Операция collect применяется к набору данных onBoard.

Прежде чем приступать к синтезу модели алгоритма, реализующего действия закодированные оператором collect примем еще одно допуще-ние.

Допущение 3.

Будем считать, что создан, и размещен в памяти массив ссылок на объекты класса String, которые будут выбраны операцией collect при работе метода getNames. Будем считать, что это одномерный массив с именем namesOnBoard. Количество элементов массива namesOnBoard равно количеству элементов массива onBoard.

Диаграмма деятельности искомого алгоритма приведена на рис. 3.7.

Рис. 3.7. Диаграмма деятельности, моделирующая работу оператора

collect в ограничении, приведенном на рис 3.6

Как видно на рис. 3.7, алгоритм, моделирующего работу оператора collect в ограничении, приведенном на рис. 3.6, представляет собой структуру типа цикл с проверкой вначале.

В начальной части алгоритма инициализируется переменная i, которая является переменной-индексом массива onBoard и одновременно параметром цикла.

Условием окончания итераций является выражение

i < onBoard.lenght

Иными словами, количество итераций равно количеству элементов массива onBoard.

При каждой итерации выполняется следующее действие

namesOnBoard[i] = onboard[i].names

Иными словами, осуществляется инициализация элементов массива namesOnBoard значениями полей names соответствующих объектов клас-са Passenger. Значение переменной i увеличивается на единицу при каж-дой итерации.

4 Примеры трансляции OCL итерационных операторов в Java код.

На рисунке 3.5. Диаграмма деятельности, моделирующая работу оператора select в ограничении, приведенном на рис 3.5

Диаграмма деятельности оператора select на языке программирования Java:

class Passenger {

public String names;

public Double annualDistance;

public String gender;

public Passenger() {

super();

}

public Passenger(String names, Double annualDistance, String gender) {

super();

this.names = names;

this.annualDistance = annualDistance;

this.gender = gender;

}

}

class Flight {

public List<Aircraft> aircraft;

public List<Passenger> passengers;

public Flight() {

super();

}

public Flight(List<Aircraft> aircraft, List<Passenger> passengers) {

super();

this.aircraft = aircraft;

this.passengers = passengers;

}

public Set<Passenger> getWinners() {

Set<Passenger> winners = new TreeSet<Passenger>();

Passenger[] onBoard = new Passenger[2];

int i = 0;

int j = 0;

while (i < onBoard.length) {

if (onBoard[i].annualDistance > 9999) {

Passenger p = onBoard[i];

winners.add(p);

j++;

}

i++;

}

return winners;

}

}

class Aircraft {

public Flight Flight;

public Integer numbOfSeats;

public Aircraft() {

super();

}

public Aircraft(Flight flight, Integer numbOfSeats) {

super();

Flight = flight;

this.numbOfSeats = numbOfSeats;

}

}4.1 Отображение диаграммы деятельности на рис. 3.7 оператора collect в код на языке программирования Java.

все, представил твой код в виде обьектов с методами, которые являются реализацией коллект и селект

class Passenger {

String names;

Double annualDistance;

String gender;

public String getNames() {

return names;

}

public void setNames(String names) {

this.names = names;

}

public Double getAnnualDistance() {

return annualDistance;

}

public void setAnnualDistance(Double annualDistance) {

this.annualDistance = annualDistance;

}

public String getGender() {

return gender;

}

public void setGender(String gender) {

this.gender = gender;

}

public Passenger() {

super();

}

public Passenger(String names, Double annualDistance, String gender) {

super();

this.names = names;

this.annualDistance = annualDistance;

this.gender = gender;

}

}

class Flight {

List<Aircraft> aircraft;

List<Passenger> passengers;

public List<Aircraft> getAircraft() {

return this.aircraft;

}

public List<Passenger> getPassengers() {

return this.passengers;

}

public Flight() {

super();

}

public Flight(List<Aircraft> aircraft, List<Passenger> passengers) {

super();

this.aircraft = aircraft;

this.passengers = passengers;

}

// select

public Set<Passenger> getWinners() {

Set<Passenger> winners = new TreeSet<Passenger>();

Passenger[] onBoard = getPassengers();

int i = 0;

int j = 0;

while (i < onBoard.length) {

if (onBoard[i].annualDistance > 9999) {

Passenger p = onBoard[i];

winners.add(p);

j++;

}

i++;

}

return winners;

}

// collect

public String[] getNames() {

String[] namesOnBoard = new String[];

int i = 0;

while (i < onBoard.length) {

String name = onBoard[i].names;

namesOnBoard[i] = name;

i++;

}

return namesOnBoard;

}

}

class Aircraft {

Flight Flight;

Integer numbOfSeats;

public Flight getFlight() {

return Flight;

}

public void setFlight(Flight flight) {

Flight = flight;

}

public Integer getNumbOfSeats() {

return numbOfSeats;

}

public void setNumbOfSeats(Integer numbOfSeats) {

this.numbOfSeats = numbOfSeats;

}

public Aircraft() {

super();

}

public Aircraft(Flight flight, Integer numbOfSeats) {

super();

Flight = flight;

this.numbOfSeats = numbOfSeats;

}

}

На рисунке 3.7 приведена диаграмма деятельности, моделирующая работу оператора collect в ограничении, приведенном на рис 3.6.

Диаграмма деятельности оператора collect на языке программирования Java:

i = 0;

while(i < onBoard.length)

{

namesOnBoard[i] = onBoard[i].names;

i++;

}

Список литературы:

1. By Jos Warmer, Anneke Kleppe. The Object Constraint Language, The: Getting Your Models Ready for MDA, Second Edition. Addison-Wesley. 2003.

2. Чмырь И.А. Объектно-ориентированное программирование. Часть 1. 2013

3. А. Ф. Верлань, И. А. Чмырь, С. Д. Кузниченко, Л. Б. Коваленко Императивное программирование и объектно-ориентированное моделирование: JAVA, UML, OCL.